// @ts-check
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
import express from 'express'

import { createRequire } from 'module';
const require = createRequire(import.meta.url);

/**
 * @param {undefined} [hmrPort]
 */
export async function createServer(
  root = process.cwd(),
  isProd = process.env.NODE_ENV === 'production',
  hmrPort
) {
  const __dirname = path.dirname(fileURLToPath(import.meta.url))
  const resolve = (/** @type {string} */ p) => path.resolve(__dirname, p)

  const indexProd = isProd
    ? fs.readFileSync(resolve('dist/client/index.html'), 'utf-8')
    : ''

  const manifest = isProd
    ? // @ts-ignore
    (await import('./dist/client/.vite/ssr-manifest.json', { assert: { type: 'json' } })).default
    : {}
  // console.log(manifest);
  const app = express()

  /**
   * @type {import('vite').ViteDevServer}
   */
  let vite
  if (!isProd) {
    vite = await (
      await import('vite')
    ).createServer({
      base: '/',
      root,
      logLevel:'info',
      server: {
        middlewareMode: true,
        watch: {
          // During tests we edit the files too fast and sometimes chokidar
          // misses change events, so enforce polling for consistency
          //在测试过程中，我们编辑文件的速度太快，有时甚至会令人窒息
          //错过更改事件，因此强制轮询以确保一致性
          usePolling: true,
          interval: 100
        },
        hmr: {
          port: hmrPort
        },
      },
      appType: 'custom',
    })
    // use vite's connect instance as middleware
    //使用vite的connect实例作为中间件
    app.use(vite.middlewares)
  } else {
    app.use((await import('compression')).default())
    app.use(
      '/',
      (await import('serve-static')).default(resolve('dist/client'), {
        index: false
      })
    )
  }

  app.use('*', async (req, res) => {
    try {
      const url = req.originalUrl
      let template, render
      if (!isProd) {
        // always read fresh template in dev
        //在开发中总是读取新的模板
        template = fs.readFileSync(resolve('index.html'), 'utf-8')
        template = await vite.transformIndexHtml(url, template)
        render = (await vite.ssrLoadModule('/src/entry-server.js')).render
      } else {
        template = indexProd
        // @ts-ignore
        render = (await import('./dist/server/entry-server.js')).render
      }
      let { html, preloadLinks } = await render(url, manifest)

      html = template
        .replace(`<!--app-meta-->`, `<meta/>`)
        .replace(`<!--app-preload-links-ssr-->`, preloadLinks)
        // 用于客户端标记服务器渲染
        .replace(`<!--app-html-ssr-->`, html);
      // console.log(html);
      res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
    } catch (e) {
      vite && vite.ssrFixStacktrace(e)
      console.log(e.stack)
      res.status(500).end(e.stack)
    }
  })

  // @ts-ignore
  return { app, vite }
}
createServer().then(({ app }) =>
  app.listen(5730, () => {
    console.log('http://localhost:5730')
  })
)
